iT邦幫忙

2025 iThome 鐵人賽

DAY 26
1

Hello, fella! 這裡是鐵匠史密斯
我們今天就講述一下 C++ 大神 javidx9 是怎麼渲染地板的吧!

地板渲染的原理

讓我們來回顧 地板、牆壁、天花板的占比

int nCeiling = (float)(nScreenHeight / 2.0) - nScreenHeight / ((float)fDistanceToWall);
int nFloor = (float)(nScreenHeight / 2.0) + nScreenHeight / ((float)fDistanceToWall)

nCeilingnFloor 可以得知,當 fDistanceToWall 越大時, nCeiling 以及 nFloor 都在螢幕高度 y = nScreenHeight / 2.0 一半的位置
又因為


if (y < nCeiling) // If the pixel is above the nCeiling -> should be ceiling
{
    screen[y * nScreenWidth + x] = ' '; // Set to space
}
else if (y > nCeiling && y <= nFloor) // If the pixel is between the nCeiling and nFloor -> should be wall
{
    screen[y * nScreenWidth + x] = nShade; // Set to wall character
}
else // If the pixel is below the nFloor -> should be floor
{
...
}

可以知道:
y < nCeiling : 屬於天花板
y > nFloor : 屬於地板

我們可以推論得出:

  • 地板的最大範圍就是從 y = nScreenHeight / 2.0y = nScreenHeight

所以,我們在渲染天花板的時候,必須要考慮到上面的這個範圍,且因為玩家視野的關係,我們地板的渲染不像是牆壁大小、牆壁的渲染 一樣,依靠fDistance,我們只要遵從一個原理就好:

  • 地板越靠近 y = nScreenHeight / 2.0(螢幕的一半) -> 代表那處的地板離我們最遠
  • ,反之,地板在螢幕最下方y = nScreenHeight -> 代表那處的地板離我們最近
    可以得出下圖:
    https://ithelp.ithome.com.tw/upload/images/20250826/20157653y6x02RevVa.png

像圖片一樣,地板由上而下可以分成三個等分(程式中分為四個等分),如下:

// Shade floor based on poroption of the way from the center to the bottom of the screen

float b{ 1.0f - (((float)y - nScreenHeight / 2.0f) / ((float)nScreenHeight / 2.0f)) };


if (b < 0.25)
    nShade = '#';
else if (b < 0.5)
    nShade = 'x';
else if (b < 0.75)
    nShade = '.';
else if (b < 0.9)
    nShade = '-';
else
    nShade = ' ';

那javidx9 大神表示的公式:

float b{ 1.0f - (((float)y - nScreenHeight / 2.0f) / ((float)nScreenHeight / 2.0f)) };

是什麼呢?
對的,簡單來說,就是相對誤差
也就是當下的 ynScreenHeight / 2.0f相對誤差,利用這個相對誤差,我們可以制定4個臨界值(threshold),讓地板渲染成不同的字元:
https://ithelp.ithome.com.tw/upload/images/20250826/20157653VQ3ODldhKB.png

最簡單的驗證方式? 好吧,實在的紙跟筆永遠是你的好朋友:
來記錄 for 迴圈中, y值增加時,是如何渲染地板的吧
https://ithelp.ithome.com.tw/upload/images/20250826/20157653OTRYVpF523.png
迭代後,我們可以知道,當 y = 40 = nScreenHegith 時, b = 0此處的地板離我們最近,就可以用自己制定的4個臨界值(thershold)來判斷要渲染哪一個字元了

if (b < 0.25)
    nShade = '#';
else if (b < 0.5)
    nShade = 'x';
else if (b < 0.75)
    nShade = '.';
else if (b < 0.9)
    nShade = '-';
else
    nShade = ' ';

https://ithelp.ithome.com.tw/upload/images/20250826/20157653Q1zy5jipVI.png
現在的畫面是不是越來越栩栩如生了呢~?

今日總結

  • 地板的範圍由 y = nScreenHeight / 2.0y = nScreenHeight
  • 牆壁依靠 fDistanceToWall 來決定高度與明暗,地板則依靠**「相對誤差 b」**來決定明暗
  • 利用 b 的值設置臨界值(threshold),即可讓地板由遠到近分層顯示不同明暗的字元 (#, x, ., -, ' ')

今天我們把地板渲染的原理拆解清楚了,其實和光學的「遠近明暗」概念很像,
看似簡單的一行公式,背後卻是利用比例與人眼視覺直覺做出的巧妙設計。

明日我們再把角色的橫移完成吧~ 我們繼續走下去~


上一篇
Day 25 | Ray Casting 渲染地板 - Part 1
下一篇
Day 27 | Ray Casting 角色橫移 - Part 1
系列文
用 C++ 實作簡易第一人稱視角遊戲:從入門到理解 Ray Casting30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言